package com.sh1604.duitang.constant;

import android.content.Context;
import android.os.Handler;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * ***********************************************************
 * author: alex
 * time: 16/7/14 上午9:38
 * name:
 * overview:
 * usage:
 * *************************************************************
 */
public class OKHttpUtils {

    private OkHttpClient mOkHttpClient;

    private Handler mHandler = new Handler();

    //=======================================================================
    // 双层验证的单例设计模式
    //=======================================================================
    //1.构造方法私有化
    private OKHttpUtils(Context context) {
        //做一些配置的信息
        //do sth...
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
//      int cacheSize = 10 * 1024 * 1024; //10Mb
        int cacheSize = 10 << 20; //10Mb
        mOkHttpClient = builder.cache(new Cache(context.getCacheDir(), cacheSize))//设置缓存目录和大小
                .connectTimeout(15, TimeUnit.SECONDS) //连接时间 15s
                .readTimeout(20, TimeUnit.SECONDS) //读取时间 20s
                .writeTimeout(20, TimeUnit.SECONDS) //写入的时间20s
                .build();
    }

    //2.暴露出一个方法，返回当前类的对象
    private static OKHttpUtils mInstance;

    public static OKHttpUtils newInstance(Context context) {
        if (mInstance == null) {
            //实例化对象
            //加上一个同步锁，只能有一个执行路径进入
            synchronized (OKHttpUtils.class) {
                if (mInstance == null) {
                    mInstance = new OKHttpUtils(context);
                }
            }
        }
        return mInstance;
    }


    //=======================================================================
    // Get异步请求方式
    //=======================================================================
    //在子线程的回调
    public void getAsyncData(String url, Callback callback, Object tag) {
        Request.Builder builder = new Request.Builder();
        if (tag != null) {
            builder.tag(tag);
        }
        Request request = builder
                .url(url)
//                .tag()
                .build();
        Call call = mOkHttpClient.newCall(request);
        call.enqueue(callback);
    }

    //在主线程的回调
    public void getAsyncMainData(String url, final MyCallBack callBack, Object tag) {
        Request.Builder builder = new Request.Builder();
        if (tag != null) {
            builder.tag(tag);
        }
        final Request request = builder
                .url(url)
                .build();
        Call call = mOkHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, final IOException e) {
                //子线程中....
//                mHandler.post(new Runnable() {
//                    @Override
//                    public void run() {
//                        callBack.onFailure(e);
//                    }
//                });

                handleFailure(e, callBack);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
                handleSuccess(result, callBack);
            }
        });
    }


    //=======================================================================
    // Post异步请求
    //=======================================================================

    //提交键值对方法
    public void postAsyncData(String url, Map<String, String> params, final MyCallBack callBack, Object tag) {
        FormBody.Builder builder = new FormBody.Builder();
        if (params != null && params.size() != 0) {
            //添加键值对
            for (Map.Entry<String, String> entry : params.entrySet()) {
                builder.add(entry.getKey(), entry.getValue());
            }
        }
        RequestBody requestBody = builder.build();
        Request.Builder builder1 = new Request.Builder();
        if (tag != null) {
            builder1.tag(tag);
        }
        Request request = builder1
                .url(url)
                .post(requestBody)
                .build();
        Call call = mOkHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handleFailure(e, callBack);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
                handleSuccess(result, callBack);
            }
        });
    }


    //=======================================================================
    // 取消tag
    //=======================================================================
    public void cancel(Object tag) {
        //准备的队列
        for (Call call : mOkHttpClient.dispatcher().queuedCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
        //正在运行的消息队列
        for (Call call : mOkHttpClient.dispatcher().runningCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
    }

    //处理失败的请求
    private void handleFailure(final IOException e, final MyCallBack listener) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                //主线程中。。。
                listener.onFailure(e);
            }
        });
    }

    //处理成功的请求
    private void handleSuccess(final String result, final MyCallBack listener) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                //主线程。。。。。。。可以更新ui等
                //只要是在这里执行的方法都是在主线程中。。。
                listener.onResponse(result);
            }
        });
    }


    //自定义的一个接口，用于请求返回数据
    //=======================================================================
    // 得想办法，把咱们自己定义的两个方法在主线程中执行。。。
    // 这样当我们在外部实现我们自己的接口的时候，实现接口中的方法就会在主线程中执行
    //=======================================================================
    public interface MyCallBack {
        //失败的回调方法
        void onFailure(IOException e);

        void onResponse(String result);
    }

}
